module;
#include <iostream>
export module Code_19_2_0;


class SumPolicy 
{
public:
    template<typename T1, typename T2>
    static void accumulate(T1& total, T2 const& value) 
    {
        total += value;
    }
};

class MultPolicy 
{
public:
    template<typename T1, typename T2>
    static void accumulate(T1& total, T2 const& value)
    {
        total *= value;
    }
};

template<typename T>
struct AccumulationTraits;

template<>
struct AccumulationTraits<int>
{
    using AccT = long;
    static constexpr AccT zero()
    {
        return 0;
    }
};


template<typename T,
         typename Policy = SumPolicy,
         typename Traits = AccumulationTraits<T>>
auto accum(T const* beg, T const* end)
{
    using AccT = typename Traits::AccT;
    AccT total = Traits::zero();
    while (beg != end) {
        Policy::accumulate(total, *beg);
        ++beg;
    }
    return total;
}

export
namespace Code_19_2_0 {

    void run()
    {
        // create array of 5 integer values
        int num[] = { 1, 2, 3, 4, 5 };
        // print product of all values
        std::cout << "the product of the integer values is " <<  accum<int, SumPolicy>(num, num + 5) << '\n';
    }
}

